#include <iostream>
#include <string>
#include <sstream>
#include "catch.hpp"
#include "Timer.h"
#include "../Priority_Queue.h"

using namespace std;

TEST_CASE("correctness of queue", "[correctness]")
{

    int minItem = 10000;
    int maxItem = 99999;

    using DB = DataBase<string, int>;

    PriorityQueue<string, int> h;
    for (int i = 37; i != 0; i = (i + 37) % maxItem)
    {
        ostringstream sout;
        sout << "hello" << i;
        if (i >= minItem)
        {
            string s = sout.str();
            h.insert(DB(s, i));
        }
    }

    DB x;
    for (int i = minItem; i < maxItem; ++i)
    {
        ostringstream sout;
        sout << "hello" << i;

        h.deleteMin(x);

        REQUIRE(x.key == sout.str());
        REQUIRE(x.data == i);
    }
}

TEST_CASE("efficiency of priority queue", "[efficiency]")
{
    int minItem = 10000;
    int maxItem = 99999;

    using DB = DataBase<string, int>;

    PriorityQueue<string, int> h;

    vector<DB> container;

    for (int i = 37; i != 0; i = (i + 37) % maxItem)
    {
        ostringstream sout;
        sout << "hello" << i;
        if (i >= minItem)
        {
            string s = sout.str();
            container.push_back(DB(s, i));
        }
    }

    SECTION("insert efficiency")
    {
        const int test_time = 10;
        for (int N = 1024; N <= 65536; N *= 2)
        {
            ostringstream event;
            event << "Insert of size " << N;
            Timer(event.str(), test_time);
            for (int j = 0; j < test_time; ++j)
            {
                for (int i = 0; i < N; ++i)
                    h.insert(container[i]);
            }
        }
    }

    SECTION("buildHeap efficiency")
    {
        const int test_time = 10;
        for (int N = 1024; N <= 65536; N *= 2)
        {
            ostringstream event;
            event << "buildHeap of size " << N;
            Timer(event.str(), test_time);
            for (int j = 0; j < test_time; ++j)
            {
                vector<DB> tmp(container.begin(), container.begin() + N);
                PriorityQueue<string, int> h_0(tmp);
            }
        }
    }

    SECTION("remove efficiency")
    {
        for (int N = 1024; N <= 65536; N *= 2)
        {
            ostringstream event;
            event << "remove of size " << N;
            PriorityQueue<string, int> h_0(container);

            Timer(event.str());

            for (int i = minItem; i < minItem + N; ++i)
            {
                ostringstream sout;
                sout << "hello" << i;
                h_0.remove(sout.str());
            }
        }
    }
}